#pragma once

#include <vector>
#include <list>
#include <algorithm>
#include <typeinfo>

using namespace std;



template <class T, class Container>
class tContainer_t {

public:
	tContainer_t() {};

	bool empty() const {
		return cont.empty();
	};

	int size() const {
		return cont.size();

	};

	void push_back(T& element) {
		cont.push_back(&element);
	};

	T* front() {
		return cont.front();
	};

	T* back() {
		return  cont.back();
	};

	T* find(const T& element) const {

		struct pred: public std::unary_function <T, bool>{
		   const T* t;
		   pred(const T &t) {this->t = &t;};
		   bool operator () ( const T *obj ) const{ //overloaded operator to check the condition.
			  return ((*t) == (*obj));
		   }
		};
		return *find_if(cont.begin(), cont.end(), pred(element));
	};

	T* remove_specific(T& value) {
		typename Container::iterator it= cont.begin();
		for (it = cont.begin(); it != cont.end(); it++) { 
			if (**it == value) {
				T* temp = *it;
				cont.erase(it);
				return temp;
			}
		}
		return NULL;	
	};
	
	bool remove_delete_specific(const T& value) {
		typename Container::iterator it= cont.begin();
		for (it = cont.begin(); it != cont.end(); it++) { 
			if (**it == value) {
				delete (*it);
				cont.erase(it);
				return true;
			}
		}
		return false;
	};

	void remove_all() {
		cont.clear();
	};
	
	void remove_delete_all() {
		typename Container::iterator it= cont.begin();
		for (it = cont.begin(); it != cont.end(); it++) { 
				delete (*it);
		}
		cont.clear();
	};


	/*might throw an exception*/
	 T& operator [] (int index) {
		 if (index < 0 || index > this->size()) throw out_of_range("Index is out of range");

		bool bRes = typeid(cont)==typeid(vector<T*>);
		if (bRes){
			vector<T*> *vec = (vector<T*> *) &cont;
			return *((*vec)[index]);
			
		}
		bRes = typeid(cont)==typeid(list<T*>);
		typename Container::iterator it= cont.begin();
		int i=0;
		for (it = cont.begin(); it != cont.end(); it++, i++) { 
				if (i==index) {
					T *temp = *it;
					return *temp;
				}
		}
		return NULL;
	};

protected:

private:
	Container cont;
	tContainer_t(const tContainer_t& rhs);
	tContainer_t& operator=(const tContainer_t& rhs);

};
